using System;
using KRPC.Service.Attributes;
using KRPC.SpaceCenter.ExtensionMethods;
using KRPC.Utils;

namespace KRPC.SpaceCenter.Services.Parts
{
    /// <summary>
    /// A solar panel. Obtained by calling <see cref="Part.SolarPanel"/>.
    /// </summary>
    [KRPCClass (Service = "SpaceCenter")]
    public class SolarPanel : Equatable<SolarPanel>
    {
        readonly ModuleDeployableSolarPanel panel;

        internal static bool Is (Part part)
        {
            return part.InternalPart.HasModule<ModuleDeployableSolarPanel> ();
        }

        internal SolarPanel (Part part)
        {
            Part = part;
            panel = part.InternalPart.Module<ModuleDeployableSolarPanel> ();
            if (panel == null)
                throw new ArgumentException ("Part is not a solar panel");
        }

        /// <summary>
        /// Returns true if the objects are equal.
        /// </summary>
        public override bool Equals (SolarPanel other)
        {
            return !ReferenceEquals (other, null) && Part == other.Part && panel == other.panel;
        }

        /// <summary>
        /// Hash code for the object.
        /// </summary>
        public override int GetHashCode ()
        {
            return Part.GetHashCode () ^ panel.GetHashCode ();
        }

        /// <summary>
        /// The part object for this solar panel.
        /// </summary>
        [KRPCProperty]
        public Part Part { get; private set; }

        /// <summary>
        /// Whether the solar panel is deployable.
        /// </summary>
        [KRPCProperty]
        public bool Deployable {
            get {
                return
                    panel.Events ["Extend"].active || panel.Events ["Retract"].active ||
                    panel.deployState == ModuleDeployablePart.DeployState.EXTENDING ||
                    panel.deployState == ModuleDeployablePart.DeployState.RETRACTING;
            }
        }

        /// <summary>
        /// Whether the solar panel is extended.
        /// </summary>
        [KRPCProperty]
        public bool Deployed {
            get {
                return
                panel.deployState == ModuleDeployablePart.DeployState.EXTENDED ||
                panel.deployState == ModuleDeployablePart.DeployState.EXTENDING;
            }
            set {
                if (!Deployable)
                    throw new InvalidOperationException ("Solar panel is not deployable");
                if (value)
                    panel.Extend ();
                else
                    panel.Retract ();
            }
        }

        /// <summary>
        /// The current state of the solar panel.
        /// </summary>
        [KRPCProperty]
        public SolarPanelState State {
            get { return panel.deployState.ToSolarPanelState (); }
        }

        /// <summary>
        /// The current amount of energy being generated by the solar panel, in
        /// units of charge per second.
        /// </summary>
        [KRPCProperty]
        public float EnergyFlow {
            get { return panel.flowRate; }
        }

        /// <summary>
        /// The current amount of sunlight that is incident on the solar panel,
        /// as a percentage. A value between 0 and 1.
        /// </summary>
        [KRPCProperty]
        public float SunExposure {
            get { return panel.sunAOA; }
        }
    }
}
